package com.linkoog.devtools.raw_index;

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationGroupManager;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.indexing.DumbModeAccessType;
import com.intellij.util.messages.MessageBusConnection;
import com.linkoog.devtools.utils.PsiClassUtils;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.util.List;

/**
 *    索引管理:  1.索引初始化     2.索引更新
 */
public class PsiRawFileIndexManager {

    private static final Logger log = Logger.getInstance(PsiRawFileIndexStartup.class);

    /**
     *    索引初始化
     */
    public static void rawFileIndexInit(Project project) {
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "DevTools fileIndex init"){
            @Override
            public void run(@NotNull ProgressIndicator progressIndicator) {
                log.warn("RawFileIndex init...");
                long startTime = System.currentTimeMillis();

                final List<PsiRawFileIndex> list = PsiRawFileIndex.EXTENSION_POINT_NAME.getExtensions(project);
                if (list.isEmpty()){
                    return;
                }

                //初始化PsiRawFileIndex索引
                for (PsiRawFileIndex psiRawFileIndex : list) {
                    ApplicationManager.getApplication().executeOnPooledThread(()->{
                        try {
                            psiRawFileIndex.init(project);
                            Disposer.register(project, psiRawFileIndex);
                        }catch (Exception e){
                            log.error("初始化失败", e);
                        }
                    });
                }

                long costTime = (System.currentTimeMillis() - startTime);
                log.warn("RawFileIndex Init cost time: " + costTime + "ms");
            }
        });
    }

    /**
     *    索引更新
     */
    public static void rawFileIndexDataScanAndBuild(Project project) {
        ApplicationManager.getApplication().invokeLater(() -> PsiDocumentManager.getInstance(project).commitAllDocuments());
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "DevTools fileIndex scan"){

            @Override
            public void run(@NotNull ProgressIndicator progressIndicator) {
                DumbService.getInstance(project).runReadActionInSmartMode(()->{
                    log.warn("rawFileIndex LoadData...");
                    long startTime = System.currentTimeMillis();

                    final List<PsiRawFileIndex> list = PsiRawFileIndex.EXTENSION_POINT_NAME.getExtensions(project);
                    if (list.isEmpty()){
                        return;
                    }


                    //预构建索引数据
                    ProjectFileIndex projectFileIndex = ProjectFileIndex.getInstance(project);
                    projectFileIndex.iterateContent(virtualFile -> {
                        return ReadAction.compute(() -> {
                            final VirtualFile sourceRootForFile = projectFileIndex.getSourceRootForFile(virtualFile);
                            if (sourceRootForFile == null){
                                return true;
                            }

                            PsiClass[] psiClassArray = PsiClassUtils.getPsiClassArray(project, virtualFile);
                            if (psiClassArray == null || psiClassArray.length == 0) return true;

                            for (PsiRawFileIndex psiRawFileIndex : list) {
                                if (psiRawFileIndex.isLasy()){
                                    continue;
                                }

                                for (PsiClass psiClass : psiClassArray) {
                                    psiRawFileIndex.afterFileChange(psiClass, false);
                                }
                            }

                            return true;
                        });
                    });


                    long costTime = (System.currentTimeMillis() - startTime);
                    log.warn("rawFileIndex LoadData cost time: " + costTime + "ms");
                    SwingUtilities.invokeLater(() -> {
                        String groupDisplayId = "com.github.linkoog.DevTools";
                        Notification notification = NotificationGroup.findRegisteredGroup(groupDisplayId).createNotification("DevTools","Http&Dubbo Service Index for IntelliJ IDEA is ready!", NotificationType.INFORMATION);
                        Notifications.Bus.notifyAndHide(notification, project);
                    });
                });
            }
        });
    }

    public static void registerFileChangeEvent(Project project){
        MessageBusConnection messageBusConnection = project.getMessageBus().connect();
        messageBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, new PsiRawFileIndexChangeListener(project));
    }


    private static void initPsiRawFileIndex(PsiRawFileIndex psiRawFileIndex, PsiClass psiClass){
        DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE.ignoreDumbMode( () -> {
            //更新 PsiClass 相关的索引
            if (psiRawFileIndex.support(psiClass)){
                try {
                    psiRawFileIndex.getCache(psiClass);
                }catch (Exception e
                ){
                    log.error("更新 PsiClass 相关的索引失败", e);
                }
                return;
            }

            //更新 PsiElement 相关的索引
            PsiElement[] children = psiClass.getChildren();
            for (PsiElement psiElement : children) {
                if (psiRawFileIndex.support(psiElement)){
                    try {
                        psiRawFileIndex.getCache(psiElement);
                    }catch (Exception e){
                        log.error("更新 PsiElement 相关的索引失败", e);
                    }
                }
            }
        });
    }


    //ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
    /* scheduledThreadPool.schedule(() -> {
            init(project);
        }, 130, TimeUnit.SECONDS);*/
}
